package com.chatplus.application.controller.admin.account;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chatplus.application.common.enumeration.AccountErrorCode;
import com.chatplus.application.common.enumeration.UserStatusEnum;
import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.common.page.PageParam;
import com.chatplus.application.controller.api.AccountApiController;
import com.chatplus.application.domain.dto.UserCustomChatConfigDto;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.entity.account.UserLoginLogEntity;
import com.chatplus.application.domain.request.AccountLoginRequest;
import com.chatplus.application.domain.request.AccountSaveRequest;
import com.chatplus.application.domain.request.AccountUpdateRequest;
import com.chatplus.application.domain.response.AccountSessionResponse;
import com.chatplus.application.domain.response.PlusPageResponse;
import com.chatplus.application.domain.response.admin.AccountLoginLogDetailResponse;
import com.chatplus.application.service.account.UserLoginLogService;
import com.chatplus.application.service.account.UserProductLogService;
import com.chatplus.application.service.account.UserService;
import com.chatplus.application.service.auth.authentication.UserAuthenticationService;
import com.chatplus.application.service.auth.request.AccountAuthenticationRequest;
import com.chatplus.application.web.basecontroller.BaseController;
import com.chatplus.application.web.satoken.helper.LoginHelper;
import com.chatplus.application.web.util.IpUtil;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import static cn.hutool.core.lang.Assert.isTrue;


/**
 * Admin用户相关API
 */
@Validated
@RestController
@RequestMapping("/api/admin")
@Tag(name = "管理员操作用户信息API", description = "用户信息API")
public class AccountAdminApiController extends BaseController {
    static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(AccountAdminApiController.class);
    private final UserAuthenticationService userAuthenticationService;
    private final UserService usersService;
    private final UserLoginLogService userLoginLogService;
    private final UserProductLogService userProductLogService;
    private final AccountApiController accountApiController;

    @Autowired
    public AccountAdminApiController(UserAuthenticationService userAuthenticationService,
                                     UserService usersService,
                                     UserLoginLogService userLoginLogService,
                                     UserProductLogService userProductLogService,
                                     AccountApiController accountApiController
    ) {
        this.userAuthenticationService = userAuthenticationService;
        this.usersService = usersService;
        this.userLoginLogService = userLoginLogService;
        this.userProductLogService = userProductLogService;
        this.accountApiController = accountApiController;
    }

    /**
     * 登录
     */
    @PostMapping("/login")
    @Operation(summary = "管理员登录")
    @SaIgnore
    public Map<String, String> login(@RequestBody @Valid AccountLoginRequest accountLoginRequest, HttpServletRequest request) {
        LOGGER.message("Admin用户发起登录请求").context("AccountRegisterRequest", accountLoginRequest).info();
        String token = getTokenString(accountLoginRequest, request, usersService, userAuthenticationService);
        isTrue(LoginHelper.isAdmin(), AccountErrorCode.ACCOUNT_NO_PERMISSION);
        return Map.of("token", token);
    }

    public static String getTokenString(AccountLoginRequest accountLoginRequest, HttpServletRequest request, UserService usersService, UserAuthenticationService userAuthenticationService) {
        isTrue(usersService.getByUsername(accountLoginRequest.getUsername()) != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        AccountAuthenticationRequest accountAuthenticationRequest = new AccountAuthenticationRequest();
        BeanUtils.copyProperties(accountLoginRequest, accountAuthenticationRequest);
        accountAuthenticationRequest.setUsername(accountLoginRequest.getUsername());
        accountAuthenticationRequest.setRemoteIp(IpUtil.getRemoteIp(request));
        return userAuthenticationService.authenticate(accountAuthenticationRequest).getAuthorizationToken();
    }

    @GetMapping("/session")
    @Operation(summary = "管理后台获取会话")
    public void session() {
        UserEntity userEntity = usersService.getById(getUserId());
        if (userEntity == null) {
            StpUtil.logout();
            throw new BadRequestException(AccountErrorCode.ACCOUNT_NOT_EXIST.getMsg());
        }
        if (userEntity.getStatus() != UserStatusEnum.OK) {
            StpUtil.logout();
            throw new BadRequestException(AccountErrorCode.ACCOUNT_HAS_LOCKED.getMsg());
        }
    }

    @GetMapping("/user/list")
    @Operation(summary = "管理员获取用户列表")
    public PlusPageResponse<AccountSessionResponse> list(@RequestParam(value = "page", required = false, defaultValue = "1") int page,
                                                         @RequestParam(value = "page_size", required = false, defaultValue = "15") int pageSize,
                                                         @RequestParam(value = "username", required = false) String username) {
        PageParam pageParam = new PageParam(page, pageSize);
        Page<UserEntity> pageDTO = usersService.page(pageParam.toPage(), Wrappers.<UserEntity>lambdaQuery()
                .like(StringUtils.isNotEmpty(username), UserEntity::getUsername, username)
                .orderByDesc(UserEntity::getCreatedAt));
        List<UserEntity> userList = pageDTO.getRecords();
        if (CollUtil.isEmpty(userList)) {
            return new PlusPageResponse<>(pageParam.getCurrent(), pageParam.getSize(),
                    0, 0, Lists.newArrayList());
        }
        List<AccountSessionResponse> responseList = userList.stream().map(accountApiController::buildAccountSession).toList();
        return new PlusPageResponse<>(pageParam.getCurrent(), pageParam.getSize()
                , pageDTO.getPages(), pageDTO.getTotal(), responseList);
    }

    @GetMapping("/user/loginLog")
    @Operation(summary = "用户登录日志")
    public PlusPageResponse<AccountLoginLogDetailResponse> loginLog(@RequestParam(value = "page", required = false, defaultValue = "1") int page,
                                                                    @RequestParam(value = "page_size", required = false, defaultValue = "15") int pageSize,
                                                                    @RequestParam(value = "username", required = false) String username) {
        PageParam pageParam = new PageParam(page, pageSize);
        Page<UserLoginLogEntity> pageDTO = userLoginLogService.page(pageParam.toPage(), Wrappers.<UserLoginLogEntity>lambdaQuery()
                .like(StringUtils.isNotEmpty(username), UserLoginLogEntity::getUsername, username)
                .orderByDesc(UserLoginLogEntity::getCreatedAt));
        List<UserLoginLogEntity> userList = pageDTO.getRecords();
        if (CollUtil.isEmpty(userList)) {
            return new PlusPageResponse<>(pageParam.getCurrent(), pageParam.getSize(),
                    0, 0, Lists.newArrayList());
        }
        List<AccountLoginLogDetailResponse> responseList = userList.stream().map(AccountLoginLogDetailResponse::build).toList();
        return new PlusPageResponse<>(pageParam.getCurrent(), pageParam.getSize()
                , pageDTO.getPages(), pageDTO.getTotal(), responseList);
    }

    @PostMapping("/user/save")
    @Operation(summary = "管理员保存更新用户信息")
    public AccountSessionResponse save(@RequestBody AccountSaveRequest accountSaveRequest) {
        String username = accountSaveRequest.getUsername();
        Long id = accountSaveRequest.getId();
        isTrue(Validator.isMobile(username) || Validator.isEmail(username), AccountErrorCode.ACCOUNT_INVALID);
        UserEntity existEntity = usersService.getByUsername(username);
        UserEntity accountEntity;
        if (id != null) {
            accountEntity = usersService.getById(accountSaveRequest.getId());
            isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
            isTrue(existEntity == null || Objects.equals(existEntity.getId(), accountEntity.getId()), AccountErrorCode.ACCOUNT_HAS_EXIST);
        } else {
            accountEntity = new UserEntity();
            isTrue(existEntity == null, AccountErrorCode.ACCOUNT_HAS_EXIST);
            accountEntity = new UserEntity();
            accountEntity.setNickname("用户@" + RandomUtil.randomString(5));
            accountEntity.setAvatar("/images/avatar/user.png");
            accountEntity.setChatConfig(new UserCustomChatConfigDto());
            accountEntity.setPassword(BCrypt.hashpw(accountSaveRequest.getPassword()));
        }
        assert accountEntity != null;
        accountEntity.setUsername(username);
        if (accountSaveRequest.getExpiredTime() != null) {
            accountEntity.setVipExpiredTime(accountSaveRequest.getExpiredTime());
        }
        accountEntity.setStatus(accountSaveRequest.isStatus() ? UserStatusEnum.OK : UserStatusEnum.DISABLE);
        accountEntity.setChatRoles(accountSaveRequest.getChatRoles());
        accountEntity.setChatModels(accountSaveRequest.getChatModels());
        accountEntity.setAdmin(accountSaveRequest.isAdmin());
        usersService.saveOrUpdate(accountEntity);
        // 动态给用户增加次数套餐，如果有的话
        userProductLogService.adminAddPowerToUser(accountEntity.getId(),
                accountSaveRequest.getPower() - userProductLogService.getUserChatPower(accountEntity.getId()), null);
        if (accountSaveRequest.getExpiredTime() != null) {
            userProductLogService.adminUpdateVidDateToUser(accountEntity.getId(), accountEntity.getVipExpiredTime(), accountSaveRequest.getExpiredTime());
        }
        return accountApiController.buildAccountSession(accountEntity);
    }

    @PostMapping("/user/resetPass")
    @Operation(summary = "管理员重置密码")
    public void resetPass(@RequestBody AccountUpdateRequest resetPassRequest) {
        isTrue(resetPassRequest.getPassword().length() >= 8 && resetPassRequest.getPassword().length() <= 16, AccountErrorCode.NEW_PASSWORD_INVALID);
        UserEntity accountEntity = usersService.getById(resetPassRequest.getId());
        isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserEntity::getId, resetPassRequest.getId());
        updateWrapper.set(UserEntity::getPassword, BCrypt.hashpw(resetPassRequest.getPassword()));
        usersService.update(updateWrapper);
    }

    @GetMapping("/user/remove")
    @Operation(summary = "管理员删除用户")
    public void remove(@RequestParam(value = "id") Long id) {
        usersService.removeById(id);
    }

    /**
     * 退出当前登录的账号
     */
    @GetMapping("/logout")
    @Operation(summary = "管理员退出登录")
    public void logout() {
        StpUtil.logout();
    }

}
